package com.kfm.util;

import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

public class DBUtil<T> {

    private static String url;
    private static String user;
    private static String password;

    private Connection conn;
    private PreparedStatement ps;


    static{
        InputStream inputStream = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");

        Properties prop = new Properties();

        try {
            prop.load(inputStream);
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            password = prop.getProperty("password");
            Class.forName(prop.getProperty("driver"));
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Connection getConnection(){
        if (conn == null){
            try {
                conn = DriverManager.getConnection(url, user, password);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return conn;
    }

    public ResultSet query(String sql, Object...params) throws SQLException {
        getConnection();

        if (sql != null){
            ps = conn.prepareStatement(sql);

            setParams(params);

            return ps.executeQuery();
        }

        return null;

    }

    public T queryOne(String sql, Class<T> cla, Object...params) throws SQLException {
        ResultSet query = query(sql, params);

        if (query != null && query.next()){
            return mapper(query, cla);
        }

        return null;

//        List<T> ts = queryList(sql, cla, params);
//        return ts.size() > 0? ts.get(0) : null;
    }

    public List<T> queryList(String sql, Class<T> cla, Object...params) throws SQLException {
        ResultSet query = query(sql, params);

        List<T> list = new ArrayList<>();
        while(query != null && query.next()){
            T mapper = mapper(query, cla);
            list.add(mapper);
        }
        return list;
    }

    private T mapper(ResultSet resultSet, Class<T> cla){
        try {
            Constructor<T> declaredConstructor = cla.getDeclaredConstructor();
            T t = declaredConstructor.newInstance();

            ResultSetMetaData metaData = resultSet.getMetaData();

            // 迭代结果集中的所有列
            for (int i = 1; i <= metaData.getColumnCount(); i ++){
                // 获取当前的 列名
                String columnLabel = metaData.getColumnLabel(i);
                Object value = resultSet.getObject(columnLabel);

                try {
                    // 数据库字段 --> java 字段
                    if (columnLabel.contains("_")){
                        // create_account => createAccount
                        columnLabel = toCamel(columnLabel);
                    }
                    // 获取列名在 class 中对应的 属性
                    PropertyDescriptor pd = new PropertyDescriptor(columnLabel, cla);
                    // 获取 setter 方法
                    Method writeMethod = pd.getWriteMethod();
                    // 设置值
                    writeMethod.invoke(t, value);
                } catch (Exception e){
                    e.printStackTrace();
                    System.err.println(columnLabel + " 属性设置值失败");
                }
            }
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private String toCamel(String label){
        // create_account => create, account
        String[] s = label.split("_");
        // 结果
        StringBuffer sb = new StringBuffer(s[0]);
        for (int i = 1; i < s.length; i++) {
            // 单词
            sb.append(s[i].substring(0, 1).toUpperCase() + s[i].substring(1));
        }
        return sb.toString();
    }

    public int update(String sql, Object...params) throws SQLException {
        getConnection();

        ps = conn.prepareStatement(sql);

        setParams(params);

        return ps.executeUpdate();
    }

    public int save(String sql, boolean isReturnKey, Object...params) throws SQLException {
        getConnection();

        ps = conn.prepareStatement(sql, isReturnKey ? Statement.RETURN_GENERATED_KEYS : Statement.NO_GENERATED_KEYS);

        setParams(params);

        int row = ps.executeUpdate();

        if (isReturnKey){
            // 获取自增主键
            ResultSet generatedKeys = ps.getGeneratedKeys();

            if (generatedKeys.next()){
                return generatedKeys.getInt(1);
            }
        }
        return row;
    }

    private void setParams(Object...params) throws SQLException {
        // 设置值
        for (int i = 0; i < params.length; i ++){
            ps.setObject(i + 1, params[i]);
        }
    }

    public void close(){
        try {
            if (ps != null){
                ps.close();
            }
            if (conn != null){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        String str = "hello_world_abc_efg";
        String[] s = str.split("_");
// 结果
        StringBuffer sb = new StringBuffer(s[0]);
        for (int i = 1; i < s.length; i++) {
            // 单词
            sb.append(s[i].substring(0, 1).toUpperCase() + s[i].substring(1));
        }
        System.out.println(sb.toString());

    }
}
